package com.anycc.cloud.core.service.impl;

import com.anycc.cloud.common.dto.easyui.Tree;
import com.anycc.cloud.common.dto.easyui.TreeBuilder;
import com.anycc.cloud.common.dto.query.PagingRequest;
import com.anycc.cloud.common.dto.query.PagingResponse;
import com.anycc.cloud.common.exception.AnyccRuntimeException;
import com.anycc.cloud.common.util.DynamicQuery;
import com.anycc.cloud.common.util.PagingUtil;
import com.anycc.cloud.common.util.PatternUtil;
import com.anycc.cloud.core.entity.Org;
import com.anycc.cloud.core.repository.AccountRepository;
import com.anycc.cloud.core.repository.OrgRepository;
import com.anycc.cloud.core.service.OrgService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

import static com.anycc.cloud.common.constant.CacheNameConstant.FIELD_CACHE_ORG_TREE;

/**
 * org service impl
 */
@Service
public class OrgServiceImpl implements OrgService {
    private TreeBuilder<Org> orgTreeBuilder = new OrgServiceImpl.OrgTreeBuilder();
    @Autowired
    private OrgRepository orgRepository;
    @Autowired
    private AccountRepository accountRepository;

    @Override
    public Org create(Org org) {
        checkNameAndCode(org);
        return orgRepository.save(org);
    }

    @Override
    @CacheEvict(value = {FIELD_CACHE_ORG_TREE},allEntries=true)//allEntries表示清除该key下所有元素
    public void delete(String id) {
        Org org = orgRepository.findById(id).orElse(null);
        if (org == null) {
            throw new AnyccRuntimeException("core.exceptions.org.not_existed");
        } else if (!org.getChildren().isEmpty()) {
            throw new AnyccRuntimeException("core.exceptions.org.delete_has_children");
        } else if (accountRepository.countByOrgId(id) > 0L) {
            throw new AnyccRuntimeException("core.exceptions.org.delete_has_account");
        } else {
            orgRepository.deleteById(id);
        }
    }

    @Override
    public Org findById(String id) {
        return orgRepository.findById(id).orElse(null);
    }

    @Override
    @CacheEvict(value = {FIELD_CACHE_ORG_TREE},allEntries=true)//allEntries表示清除该key下所有元素
    public Org update(Org org) {
        checkNameAndCode(org);
        return orgRepository.save(org);
    }

    @Override
    public PagingResponse<Org> findByPaging(Org org, PagingRequest pagingRequest) {
        Page<Org> page = orgRepository
                .findAll(new DynamicQuery<Org>().build((predicates, root, query, cb) -> {
                    if (StringUtils.isNotBlank(org.getName())) {
                        predicates.add(cb.like(root.get(Org.FIELD_NAME), PatternUtil.trimLike(org.getName())));
                    }
                    Optional.ofNullable(org.getParent()).ifPresent(parent ->
                            predicates.add(cb.equal(root.get(Org.FIELD_PARENT).get(Org.FIELD_ID), parent.getId()))
                    );
                }), PagingUtil.buildPageRequest(pagingRequest));
        return PagingUtil.buildPagingResponse(pagingRequest, page);
    }

    @Override
    @Cacheable(value = FIELD_CACHE_ORG_TREE, key = "'org' +'_'+ #root.method.name")
    public List<Tree> tree() {
        return orgTreeBuilder.buildTreeList(orgRepository.findAll(Sort.by(Sort.Direction.ASC, "name")));
    }

    @Override
    public List<Tree> parentTree(String orgId) {
        Org currentOrg = orgRepository.findById(orgId).orElse(null);
        return orgTreeBuilder.buildParentTreeList(orgRepository.findAll(Sort.by(Sort.Direction.ASC, "name")), currentOrg);
    }

    private void checkNameAndCode(Org org) {
        if (org != null && !StringUtils.isBlank(org.getName())) {
            if (org.getCode() != null) {
                Org dbOrg = orgRepository.findByCode(org.getCode());
                if (dbOrg != null && !StringUtils.equals(dbOrg.getId(), org.getId())) {
                    throw new AnyccRuntimeException("core.exceptions.org.code_existed,code=" + org.getCode());
                }
            }
        } else {
            throw new AnyccRuntimeException("core.exceptions.org.name_required");
        }
    }

    private class OrgTreeBuilder extends TreeBuilder<Org> {
        private OrgTreeBuilder() {
        }

        protected Org getParent(Org entity) {
            return entity.getParent();
        }

        protected List<Org> getChildren(Org entity) {
            return entity.getChildren();
        }

        protected String getNodeId(Org entity) {
            return entity.getId();
        }

        protected String getNodeText(Org entity) {
            return entity.getName();
        }
    }
}
